package com.bthdung.studios.lesson12.framework.program;

import java.util.Hashtable;

import android.opengl.GLES20;
import android.util.Log;

public class Effect
{
	protected int vShader;
	protected int fShader;

	// Slow when stress-tested, using direct index is much faster
	protected Hashtable<String, Integer> attributes;
	protected Hashtable<String, Integer> uniforms;;

	public Effect(String vShaderCode, String fShaderCode)
	{
		vShader = glLoadShader(GLES20.GL_VERTEX_SHADER, vShaderCode);
		fShader = glLoadShader(GLES20.GL_FRAGMENT_SHADER, fShaderCode);
	}

	// only call after linking
	public void glRetrieveUniforms(int program)
	{
		if (uniforms != null) uniforms.clear();
		else
			uniforms = new Hashtable<String, Integer>();

		int[] total = new int[] { -1 };
		GLES20.glGetProgramiv(program, GLES20.GL_ACTIVE_UNIFORMS, total, 0);

		for (int i = 0; i < total[0]; ++i)
		{
			int[] length = new int[] { 0 };
			int[] size = new int[] { 0 };
			int[] type = new int[] { 0 };
			byte[] name = new byte[50];

			GLES20.glGetActiveUniform(program, i, 50, length, 0, size, 0, type, 0, name, 0);

			uniforms.put(new String(name, 0, length[0]), i);
		}
	}

	// only call after linking
	public void glRetrieveAttributes(int program)
	{
		if (attributes != null) attributes.clear();
		else
			attributes = new Hashtable<String, Integer>();

		int[] total = new int[] { -1 };
		GLES20.glGetProgramiv(program, GLES20.GL_ACTIVE_ATTRIBUTES, total, 0);

		for (int i = 0; i < total[0]; ++i)
		{
			int[] length = new int[] { 0 };
			int[] size = new int[] { 0 };
			int[] type = new int[] { 0 };
			byte[] name = new byte[50];

			GLES20.glGetActiveAttrib(program, i, 50, length, 0, size, 0, type, 0, name, 0);

			attributes.put(new String(name, 0, length[0]), i);
		}
	}

	// call only after retrieveAttributes
	public void glActivateAttributes()
	{
		for (Integer id : attributes.values())
			GLES20.glEnableVertexAttribArray(id);
	}

	public int glGetAttributePosition(String name)
	{
		return (int) attributes.get(name);
	}

	public int glGetUniformPosition(String name)
	{
		return uniforms.get(name);
	}

	// Slow when stress-tested, using direct index is much faster
	public void glSetUniformMatrix4fv(String name, float[] value)
	{
		glSetUniformMatrix4fv(uniforms.get(name), value);
	}

	public void glSetUniformMatrix4fv(int index, float[] value)
	{
		GLES20.glUniformMatrix4fv(index, 1, false, value, 0);
	}

	public int glGetVShader()
	{
		return vShader;
	}

	public int glGetFShader()
	{
		return fShader;
	}

	protected static int glLoadShader(int type, String code)
	{
		int shader = GLES20.glCreateShader(type);
		if (shader == 0) throw new RuntimeException("Error Creating shader.");

		GLES20.glShaderSource(shader, code);
		GLES20.glCompileShader(shader);

		int[] params = new int[] { 0 };
		GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, params, 0);

		if (params[0] == 0)
		{
			String log = GLES20.glGetShaderInfoLog(shader);
			GLES20.glDeleteShader(shader);
			Log.e("Shader", log);

			throw new RuntimeException("Error loading shader.");
		}

		return shader;
	}

}
